package com.lxm.framework.mybatisplus.util;

import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.lxm.framework.mybatisplus.common.SqlConstant;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * @Author: Lys
 * @Date 2022/2/25
 * @Describe
 **/
public class InterceptUtils {

    public static void setFieldTenantId(BoundSql boundSql, MetaObject metaObject) {
        var tid = metaObject.getValue(SqlConstant.TID);
        if (Objects.isNull(tid)) {
            setFieldValueByName(boundSql, SqlConstant.TID, 1, metaObject);
        } else {
            setFieldValueByName(boundSql, SqlConstant.TID, tid, metaObject);
        }
    }

    public static void setFieldUpdatedBy(BoundSql boundSql, MetaObject metaObject) {
        var byId = metaObject.getValue(SqlConstant.UPDATED_BY_ID);
        if (Objects.isNull(byId)) {
            setFieldValueByName(boundSql, SqlConstant.UPDATED_BY_ID, 1, metaObject);
        } else {
            setFieldValueByName(boundSql, SqlConstant.UPDATED_BY_ID, byId, metaObject);
        }
    }

    public static void setFieldCreatedBy(BoundSql boundSql, MetaObject metaObject) {
        var byId = metaObject.getValue(SqlConstant.CREATED_BY_ID);
        if (Objects.isNull(byId)) {
            setFieldValueByName(boundSql, SqlConstant.CREATED_BY_ID, 1, metaObject);
        } else {
            setFieldValueByName(boundSql, SqlConstant.CREATED_BY_ID, byId, metaObject);
        }
    }

    public static void setFieldUpdatedTime(BoundSql boundSql, MetaObject metaObject, LocalDateTime time) {
        var cat = metaObject.getValue(SqlConstant.UPDATED_AT);
        if (Objects.isNull(cat)) {
            setFieldValueByName(boundSql, SqlConstant.UPDATED_AT, time, metaObject);
        } else {
            setFieldValueByName(boundSql, SqlConstant.UPDATED_AT, cat, metaObject);
        }
    }

    public static void setFieldCreatedTime(BoundSql boundSql, MetaObject metaObject, LocalDateTime time) {
        var cat = metaObject.getValue(SqlConstant.CREATED_AT);
        if (Objects.isNull(cat)) {
            setFieldValueByName(boundSql, SqlConstant.CREATED_AT, time, metaObject);
        } else {
            setFieldValueByName(boundSql, SqlConstant.CREATED_AT, cat, metaObject);
        }
    }

    public static void setFieldDeletedTime(BoundSql boundSql, MetaObject metaObject, LocalDateTime time) {
        Object finalTime = Objects.isNull(time) ? SqlConstant.DELETED_TIME_DEFAULT : time;
        setFieldValueByName(boundSql, SqlConstant.DELETED_TIME, finalTime, metaObject);
    }

    public static void setFieldDeleted(BoundSql boundSql, MetaObject metaObject, Boolean flag) {
        final boolean mark = !Objects.isNull(flag) && flag;
        setFieldValueByName(boundSql, SqlConstant.DELETED, mark, metaObject);
    }

    public static boolean isDeleteMapper(String statementId) {
        String pureStatementId = StringUtils.substringAfterLast(statementId, ".");
        return pureStatementId.startsWith(SqlConstant.FLAG_DELETE) || pureStatementId.startsWith(SqlConstant.FLAG_DELETE_SHORT) || pureStatementId.startsWith(SqlConstant.FLAG_REMOVE);
    }

    public static boolean escape(String statementId) {
        return StringUtils.endsWith(statementId, SqlConstant.FLAG_ESCAPE);
    }

    private static void setFieldValueByName(BoundSql boundSql, String fieldName, Object fieldVal, MetaObject metaObject) {
        if (Objects.isNull(fieldVal)) {
            return;
        }
        boundSql.setAdditionalParameter(fieldName, fieldVal);
        if (metaObject.hasSetter(fieldName) && metaObject.hasGetter(fieldName)) {
            setFieldValue(fieldName, fieldVal, metaObject);
        } else if (metaObject.hasGetter(Constants.ENTITY)) {
            var et = metaObject.getValue(Constants.ENTITY);
            if (Objects.nonNull(et)) {
                var etMeta = SystemMetaObject.forObject(et);
                if (etMeta.hasSetter(fieldName)) {
                    setFieldValue(fieldName, fieldVal, metaObject);
                }
            }
        }
    }

    private static void setFieldValue(String fieldName, Object fieldVal, MetaObject metaObject) {
        if (SqlConstant.TID.equals(fieldName) && metaObject.getValue(fieldName) != null && (int) metaObject.getValue(fieldName) >= 0) {
            return;
        }
        metaObject.setValue(fieldName, fieldVal);
    }

    public static String genKey(String statementId, String originalSql) {
        var tid = 1;
        return (tid + "_" + statementId + "_" + originalSql);
    }
}
